<template>
  <div class="monaco-editor-container" ref="editorContainer"></div>
</template>

<script setup lang="ts">
import { ref, onMounted, onBeforeUnmount, watch } from 'vue'
import * as monaco from 'monaco-editor'
import editorWorker from 'monaco-editor/esm/vs/editor/editor.worker?worker'
import tsWorker from 'monaco-editor/esm/vs/language/typescript/ts.worker?worker'
import { useElementSize } from '@vueuse/core'

// 设置Monaco Editor Worker
self.MonacoEnvironment = {
  getWorker(_, label) {
    if (label === 'typescript' || label === 'javascript') return new tsWorker()
    return new editorWorker()
  }
}

interface Props {
  modelValue: string // v-model值
  language?: string // 编程语言
  theme?: 'vs' | 'vs-dark' | 'hc-black' | 'hc-light' // 主题
  options?: monaco.editor.IStandaloneEditorConstructionOptions // 编辑器选项
  readOnly?: boolean // 是否只读
}

const props = withDefaults(defineProps<Props>(), {
  modelValue: '',
  language: 'Java',
  theme: 'vs-dark',
  readOnly: false,
  options: () => ({})
})

const emit = defineEmits<{
  (e: 'update:modelValue', value: string): void
  (e: 'editorDidMount', editor: monaco.editor.IStandaloneCodeEditor): void
  (e: 'change', value: string): void
}>()

// 编辑器引用
const editorContainer = ref<HTMLElement | null>(null)
const { width, height } = useElementSize(editorContainer)
let editor: monaco.editor.IStandaloneCodeEditor | null = null

// 初始化编辑器
onMounted(() => {
  if (editorContainer.value) {
    const defaultOptions: monaco.editor.IStandaloneEditorConstructionOptions = {
      value: props.modelValue,
      language: props.language.toLowerCase(),
      theme: props.theme,
      automaticLayout: true,
      scrollBeyondLastLine: false,
      minimap: { enabled: true },
      scrollbar: {
        useShadows: false,
        verticalScrollbarSize: 10,
        horizontalScrollbarSize: 10
      },
      fontSize: 14,
      fontFamily: '"Fira Code", "Source Code Pro", "Consolas", "Monaco", monospace',
      lineNumbers: 'on',
      wordWrap: 'on',
      readOnly: props.readOnly,
      ...props.options
    }

    editor = monaco.editor.create(editorContainer.value, defaultOptions)

    // 监听内容变化
    editor.onDidChangeModelContent(() => {
      const value = editor?.getValue() || ''
      emit('update:modelValue', value)
      emit('change', value)
    })

    // 通知组件挂载完成
    emit('editorDidMount', editor)
  }
})

// 监听props变化
watch(() => props.modelValue, (newValue) => {
  if (editor && newValue !== editor.getValue()) {
    editor.setValue(newValue)
  }
})

watch(() => props.language, (newLanguage) => {
  if (editor) {
    const model = editor.getModel()
    if (model) {
      monaco.editor.setModelLanguage(model, newLanguage.toLocaleLowerCase())
    }
  }
})

watch(() => props.theme, (newTheme) => {
  if (editor) {
    monaco.editor.setTheme(newTheme)
  }
})

watch(() => props.readOnly, (newValue) => {
  if (editor) {
    editor.updateOptions({ readOnly: newValue })
  }
})

// 响应容器大小变化
watch([width, height], () => {
  if (editor) {
    editor.layout()
  }
})

// 组件销毁时清理资源
onBeforeUnmount(() => {
  if (editor) {
    editor.dispose()
    editor = null
  }
})

// 暴露编辑器实例给父组件
defineExpose({
  editor: () => editor
})
</script>

<style scoped>
.monaco-editor-container {
  width: 100%;
  height: 100%; /*让外部来决定高度*/
  border: 1px solid var(--color-border, #ccc);
  overflow: hidden;
}
</style> 